home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-04-27 | 62.5 KB | 1,839 lines |
- 7 SERIAL DEVICE
-
- 7.1 INTRODUCTION
-
- All Amiga models have a serial port to which you can connect
- external devices like a modem, scanner or a printer with a
- serial interface. Data can be sent in both directions, in
- several different formats, like seven or eight bits, with
- or without error checking etc.
-
- On the Amiga the serial port consists of a 25 pin connector,
- and can communicate with baud rate up to 32250. It is the
- custom chip called "Paula" which contains a Universal
- Asynchronous Receiver/Transmitter (UART) that takes care of
- all serial data transmissions. The chip itself can manage
- up to one million bits per second, but at that speed the data
- buffer would be filled before the system had time to react,
- and normal cables can not manage to transmit more than
- 100,000 - 200,000 bits per second.
-
- Baud rates between 1200 and 9600 are in most cases more than
- sufficient, and at that speed the computer will still be able
- to multitask properly.
-
-
-
- 7.2 THE SERIAL PORT
-
- The serial port sends and receives data in streams of bits.
- In theory only one physical wire would therefore be required,
- but there have been several extra cables added to send and
- receive special information as well as to supply external
- devices with power (+12V) and so on.
-
- Since all data is sent bit by bit, and not as with the parallel
- port which sends one byte (8 bits) each time, it is rather
- slow. (Well at least not as fast as the parallel port, which
- is fully documented in the next chapter.) However, since
- some applications only works with one line, for example
- the modems which are connected to the telephone system,
- serial communication is easier to handle. Serial cables are
- also much cheaper.
-
- Although only one line is required there is a whole 25-pin
- connector on the Amiga. Normal applications like a modem, or
- a scanner only needs some of the lines, but since there are
- so many possible lines to use, a lot of special equipment can
- be connected to the serial port. (See illustration "RS-232".)
-
-
-
- 7.2.1 BYTE TO BITS AND VICE VERSA
-
- Since the serial device only sends a stream of bits, a special
- chip has to convert the data (bytes) to bits (8). The character
- "A" would for example be transformed to 01000001 and "B" to
- 01000010 and so on. Of course the chip must also be able to
- do the opposite, to convert an incoming stream of bits to
- bytes.
-
- --------
- A (64) <- | | <- 01000001 (Receiving data)
- | UART |
- D (68) -> | | -> 01000100 (Transmitting data)
- --------
-
-
- The special chip that takes care of this is the "Universal
- Asynchronous Receiver/Transmitter" usually referred to as
- "UART". (See illustration "UART") Luckily we do not need to
- bother too much about this. However, it is good to know what
- is actually happening.
-
-
-
- 7.2.2 PIN ASSIGNMENT
-
- The Amiga's serial port is a 25-pin D-female-type connector.
- Below is an almost complete list of the pin assignment,
- together with a short description. (See illustration "RS-232".)
-
- Pin Amiga RS232 HAYES Direction Type Description
- -------------------------------------------------------------------
- 1 SHIELD GND GND - Standard Ground
- 2 TXD TXD TXD Out Standard Transmit data
- 3 RXD RXD RXD In Standard Receive data
- 4 RTS RTS x - Out Standard Request to send
- 5 CTS CTS x CTS In Standard Clear to send
- 6 DSR DSR x DSR In Standard Data set ready
- 7 GND GND GND - Standard Signal ground
- 8 DCD DCD DCD In Standard Carrier detect
- 9 +12V - - - Amiga +12 Volt
- 10 -12V - - - Amiga -12 Volt
- 11 AUDO - - Out Amiga Audio output
- 12 - S.DS SI + - Speed indicate
- 13 S.CTS - + - RS232 code
- 14 - S.TXD - + - RS232 code
- 15 - TXC - + - RS232 code
- 16 - S.RXD - + - RS232 code
- 17 - RXC - + - RS232 code
- 18 AUDI - - In Amiga Audio in (not used)
- 19 - S.RTS - + - RS
- 20 DTR DTR x DTR Out Standard Data terminal ready
- 21 - SQD - - * (A1000 +5V)
- 22 RI RI RI In Standard Ring indicator
- 23 - SS - - * (A1000 +12V)
- 24 - TXC1 - - - 3.58 MHz clock
- 25 - - - - Amiga Reset (A1000)
-
- (x) Used only if you have set the "seven-wire flag". Se below
- for more information.
-
- WARNING! Pin 21 and 23 are connected to the power supply on
- the old Amiga 1000s (+5V and +12V). On all other models the
- power is sent through pin 9 and 10. Be careful with this if
- you intend to make serial cables! We do not want to burn the
- user's external devices, do we?
-
-
-
- 7.2.3 THE DATA STREAM
-
- Since all data is sent and received in a stream of bits, the
- UART chip needs to know when each new byte (set of 8 bits) is
- coming in. To make this possible, following rules have been
- stated: (See illustration "Serial Bits".)
-
- 1. When no data is sent, a mark bit (1) is sent over and over.
-
- 2. Just before a byte is sent, a start bit (0) is transmitted.
- The receiver will now know that seven or eight bits (depends
- on what type of device it is) of data will be received.
-
- 3. An optional "parity" bit will come directly after the
- data bits. The parity bit is used for error checking. The
- receiver may use "even", "odd" or no parity at all. If
- the receiver is using even parity, the sender should set
- the parity bit to 1 if the remainder of all data bits
- divided by two is 0, else the parity bit should be set to
- 0. If the receiver is using odd parity, the sender should
- set the parity bit to 0 if the remainder of all data bits
- divided by two is 0, else the parity bit should be set to
- 1. If the receiver does not use parity checking, either
- set the parity bit to 0 or do not send any parity bit at
- all.
-
- 4. Finally we need to send one (or two) stop bit(s) to tell
- the receiver that the last data bit has been sent.
-
-
- ...1 0 0 0 1 0 0 0 1 0 1 0 0 0 1... -> -> ->
- ..._ _ _ _ _...
- \_____/ \_____/ \_/ \_____/
- ^ ^
- | ^ ^ ^ 8 7 6 5 4 3 2 1 0 ^ |
- | | | | <-- Data bits --> | Mark bit(s)
- | | | | (7 or 8 bits) |
- | | | | Start bit
- | | | |
- | \ / Parity bit (We use even parity, hence 0)
- | |
- | One or two stop bits
- |
- Mark bit(s)
-
-
- Even parity: The sum of the data bits is divided by two, and
- if the remainder is 0, the parity bit should be
- set to 1. If the remainder is 1, the parity bit
- should be set to 0.
-
- 10100110 = 4 bits are set. 4/2 remainder = 0 -> parity = 1
- 01110110 = 5 bits are set. 5/2 remainder = 1 -> parity = 0
-
-
- Odd parity: The sum of the data bits is divided by two, and
- if the remainder is 0, the parity bit should be
- set to 0. If the remainder is 1, the parity bit
- should be set to 1.
-
- 10100110 = 4 bits are set. 4/2 remainder = 0 -> parity = 0
- 01110110 = 5 bits are set. 5/2 remainder = 1 -> parity = 1
-
-
- The nice thing about the serial device is that we do not need
- to bother about this. (So why did I write it?) You only have
- to tell the device if you want to use parity, and if so if it
- should use even (default) or odd parity. You should also tell
- the serial device if you want to send seven or eight data bits,
- and one or two stop bits. Once you have told the device what
- you want, you do not need to think about it any more.
-
-
-
- 7.3 THE SERIAL DEVICE
-
- The Serial Port is a limited resource it that sense that there
- exist (normally) only one port. There may however be several
- programs running at the same time which all want to use the
- serial port. To make this possible they all have to coordinate
- their work with the port. That is the serial device's main
- task.
-
- You can tell the device that you want a shared access, which
- means that other programs may also use the serial port, or if
- you want exclusive access, no other programs may use the
- device. It is then up to the device if it will accept your
- demands or else deny you the right to use the serial port.
- (Another task may have exclusive access.)
-
- Once you have been allowed to use the serial port, you should
- send all your demands to the serial device, and it will take
- care of everything. You only have to give it some information
- like how it should work (eight or seven bits data, parity?
- one or two stop bits, baud rate etc...) and where data should
- be fetched/stored.
-
-
-
- 7.3.1 PREPARE THE SERIAL DEVICE
-
- Before you should open the serial device you need to decide if
- you want exclusive or shared access, and if you want to use the
- special RTS/CTR, DTR/DSR ("seven-wire-mode").
-
- 1. If you want shared access, other programs may also use the
- serial port, set the flag SERF_SHARED. (Se below.) If you
- want exclusive access you do not need to set any flags,
- since it is the default mode.
-
- 2. If you want to use the RTS/CTR, DTR/DSR handshaking
- protocol ("seven-wire-mode") set the flag SERF_7WIRE.
-
-
-
-
- 7.3.2 OPEN THE SERIAL DEVICE
-
- As with all devices you have to open a message port through
- which the serial device can talk to you, and allocate a
- request block (a IOExtSer structure), before you may open
- the device itself.
-
- 1. Open a message port: (Since it is only our task and the
- device that will use the message port, we do not need
- to make it "public", hence no name. Priority should as
- usual be set to 0, normal priority.)
-
- struct MsgPort *replymp;
-
- replymp = (struct MsgPort *)
- CreatePort( NULL, 0 );
-
- if( !replymp )
- clean_up( "Could not create the reply port!" );
-
-
- 2. Allocate a request block of type IOExtSer structure.
- (The IOExtSer structure is an extended version of the
- normal request block, and should therefore be allocated
- with help of the CreateExtIO() function with the size
- set to sizeof( struct IOExtSer ).
-
- struct IOExtSer *serial_req;
-
- serial_req = (struct IOExtSer *)
- CreateExtIO( replymp, sizeof( struct IOExtSer ) );
-
- if( !serial_req )
- clean_up( "Not enough memory!" );
-
-
- Once the message port and the request block have successfully
- been created, you should set the desired flags which were
- explained above, and then open the serial device.
-
- 3. Set desired flags (only SERF_SHARED and SERF_7WIRE are
- accepted), and open the device.
-
- UBYTE error;
-
- serial_req->io_SerFlags = SERF_SHARED|SERF_7WIRE;
-
- error = OpenDevice( SERIALNAME, 0, serial_req, 0 );
-
- if( error )
- clean_up( "Could not open the Serial Device!" );
-
-
-
- 7.3.3 SET SERIAL PARAMETERS
-
- Once the serial device has successfully been opened you should
- set desired parameters like baud rate, seven or eight data bits
- and so on. To set these parameters you initialize the request
- block as described below, set the flag SDCMD_SETPARMS and
- tells EXEC to execute your request with a DoIO() command.
-
- Here is a list of parameters that should be initialized: (We
- assume you have already opened the device as described above,
- and have also created an IOExtSer structure with a pointer
- named "ioreq" to it.
-
- 1. The serial device collects data and stores it in a
- temporary buffer. Because of this it can read a lot of
- data without any interruption, and once there is a break
- the data in this temporary buffer is moved to the real
- data buffer. The temporary buffer should be at least
- 512 bytes, but more is recommended, especially if you
- want to collect a lot of data at high speed.
-
- This temporary buffer is automatically created by the
- serial device, and also automatically deallocated when
- you close the device. If you have set one buffer size,
- and later on changes the size, the old buffer will be
- removed and a new buffer allocated. All data will then
- be lost, so do not change the size of the buffer while
- you are still collecting data.
-
- The size is set in the io_RBufLen field of the request
- structure. The size must be at least 512, but other
- recommended sizes are 1024, 2048, 4096, 8192 or 16384.
- To set the internal input buffer size to 8192 bytes do
- like this:
-
- ioreq->io_RBufLen = 8192;
-
-
- 2. You must tell the serial device at what speed it should
- communicate (how many bits per second). It is important
- that both the sender and receiver are using the same
- speed.
-
- You set the desired speed by initializing the io_Baud
- field to one of the following baud rates (you may use
- other speeds, but most applications expect you to use
- on of the recommended speeds, and if it is to fast data
- can be lost or corrupted): 110, 300, 1200, 2400, 4800,
- 9600, 19200 or 31250. To set the baud rate to 9600 do
- like this:
-
- ioreq->io_Baud = 9600;
-
-
- 3. Your program or the external device you are communicating
- with can send a "break message", which will pause the
- transmission for a specified time. This is useful if you
- have received to many messages and you can not answer all
- of them before more are arriving. A small break would in
- this case be appreciated. A break signal simply stops the
- communication for a specified number of microseconds.
-
- You can set the number of microseconds the communication
- should be down after a break signal by initializing the
- io_BrkTime field. To set the break time to half a second
- do like this:
-
- ioreq->io_BrkTime = 500000;
-
-
- 4. If you want to read normal ASCII characters you only need
- the first seven bits, and should therefore only try to
- collect seven data bits instead of eight. However,
- sometimes you want to receive whole bytes, and should then
- collect all eight data bits.
-
- To set the number of bits you want to read each time you
- initialize the io_ReadLen field accordingly. To read eight
- data bits do like this:
-
- ioreq->io_ReadLen = 8;
-
-
- 5. Since you sometimes only want to send 7 data bits, but
- other times want send all 8 data bits, you should
- initialize the io_WriteLen field accordingly. To write
- eight bits do like this:
-
- ioreq->io_WriteLen = 8;
-
-
- 6. After each character you need to send one or two stop
- bit(s), depending on what the other device expect.
- Normally you only use one stop bit, but if you are using
- seven data bits it happens that you should use two stop
- bits. To tell the serial device to use one stop bit to
- like this:
-
- ioreq->io_StopBits = 1;
-
-
- 7. There exist some special modes that are selected by
- setting some serial flags. Here is a complete list of
- possible flags together with a short description:
-
- SERF_XDISABLED Set this flag if you want to turn off
- the XON-XOFF feature. Default is on.
-
- SERF_EOFMODE Set this flag if you want the Serial
- Device to send/collect data until it
- finds one of the eight specified
- "end-of-file" characters. (See below
- for more information.)
-
- SERF_SHARED Set this flag if you want to share the
- serial port with other programs. Note
- that this flag should only be used
- BEFORE you have opened the device, and
- should NOT be changed later on. If you
- want to change status you should close
- the serial device, alter the status and
- then try to open it again.
-
- SERF_RAD_BOOGIE Set this flag if you want to use the
- serial port at high speed. When this
- flag is set no parity is used, xON/xOFF
- handling is turned off, no break signals
- are allowed, and finally only eight-bit
- characters are used. When you need fast
- communication set this flag, but
- remember that the data will then not be
- error checked, and break signals are
- ignored.
-
-
- SERF_QUEUEDBRK Set this flag if you want break commands
- to be queued along with all other
- signals. The default is that a break
- command interrupts the process
- immediately.
-
- SERF_7WIRE If the flag is set, the seven-wire
- "handshaking" mode will be used.
- (Default is three-wire.) With this flag
- set you can use the RS232 RTS/CTS,
- DTR/DSR commands. This flag should only
- be used BEFORE when you have opened the
- serial device, and should NOT be changed
- after that. To change this mode, you
- must close the device, set the desired
- mode and then try to open it again.
-
- SERF_PARTY_ODD Set this flag if you want to use odd
- parity. (The default setting is even
- parity.)
-
- SERF_PARTY_ON Parity checking/writing is turned on.
- (The sum of all data bits are divided by
- two, and the remainder is the parity
- bit. If even parity is used the bit will
- be set to 1 if the remainder is even. If
- odd parity is used the parity bit will
- be set to 0 if the remainder is even.
-
- You set desired flags in the io_SerFlags filed of the
- request structure. If you want to set several flags, put
- a "|" ("binary-OR") between. To set the parity on, and
- use the end of character mode, do like this:
-
- ioreq->io_SerFlags = SERF_PARTY_ON | SERF_EOFMODE;
-
- Note! If you do not want to set any flags, remember to set
- the field to 0. If you do not make sure it is empty, some
- flags might accidentally be set.
-
-
- 8. There exist a special field where more serial flags can
- be used in the future. For the moment there exist only two
- flags for this field.
-
- SEXTF_MSPON Set this flag if you want to use mark-space
- parity rather than odd-even parity.
-
- SEXTF_MARK If this and the SEXTF_MSPON flag is set, it
- will Mark.
-
- If you want to use the mark-space method, with mark, do
- like this:
-
- ioreq->io_ExtFlags = SEXTF_MSPON | SEXTF_MARK;
-
- Note! If you do not want to set any of these flags, remember
- to set the field to 0!
-
-
- 9. If you have set the flag "SERF_EOFMODE", the serial device
- will send/collect data until it finds one of eight
- specified "end-of-file" characters. These eight characters
- are stored in a IOTArray structure which look like this:
-
- struct IOTArray
- {
- ULONG TermArray0;
- ULONG TermArray1;
- };
-
- Each ULONG data consists of four bytes, and in total you
- can store eight bytes (end-of-file characters) in the
- array. To make the checking routine efficient you must
- store the characters in descending order! To copy the
- desired characters into the array do like this:
-
- /* Here is an array with all EOF characters: */
- /* NOTE! They MUST be in descending order! */
- UBYTE eof_char[8]={ 0x54, 0x32, 0x16, 0x15,
- 0x12, 0x03, 0x00, 0x00 };
-
- /* Declare a unsigned byte pointer: */
- UBYTE *ptr;
-
- /* Simple loop variable: */
- int loop;
-
- ...
-
- /* Get the address of the IOTArray: */
- ptr = (UBYTE *) &(ioreq->io_TermArray);
-
- /* Set all eight end of file characters: */
- for( loop=0; loop < 8; loop++ )
- {
- /* Copy character after character: */
- *ptr = eof_chars[ loop ];
-
- /* Step one byte foreward: */
- ptr++;
- }
-
-
- Once you have set all desired parameters in the request block
- (IOExtSer structure) you set the IO command to SDCMD_SETPARAMS
- and tell the serial device to do your request by calling the
- DoIO() function. If something went wrong DoIO() will return
- with an error number, else 0 is returned which means that your
- request have successfully been executed. (See below for a
- complete list of error messages.)
-
- ioreq->IOSer.io_Command = SDCMD_SETPARAMS;
-
- error = DoIO( ioreq );
-
-
-
- 7.3.4 READ DATA
-
- When you want to read data from the serial port, you have to do
- four things. First you have to give the serial device a pointer
- to a buffer where all data which you read will be stored.
- (This memory buffer is not the same as the serial device's own
- temporary input buffer that was explained above.)
-
- Secondly you have to tell the device how many bytes/characters
- you want to read. You do it by either telling the device
- exactly how many characters you want to read, or set the
- length to -1 which means you want to read continuously and stop
- first when an end-of-file characters have been found. (Remember
- to set the flag "SERF_EOFMODE", or the serial device will not
- check for termination characters.)
-
- Thirdly you have to set the command flag "CMD_READ", which
- tells the serial device that you want to read data from the
- serial port.
-
- Finally you tell the serial device to do your request. You can
- either put your program to sleep while the serial device is
- reading data with a DoIO() call, or you use the SendIO()
- function and continue to do something while all data is
- collected. There exist even a special "quick" mode which
- should be used if very fast communication is needed.
-
- Here is an example on how to read data: (Your program will be
- put to sleep while the data is collected.)
-
- error: (UBYTE) is a simple unsigned byte variable.
-
- ioreq: (struct IOExtSer *) is a pointer to an IOExtSer
- structure.
-
- data: (BYTE) is a pointer to a block of memory where all
- data which is collected will be stored. Note that the
- serial device will not check if it sends more data
- than actually can be stored in the buffer. Innocent
- memory can be corrupted if you do not make the buffer
- big enough!
-
-
- /* We want to read some data: */
- ioreq->IOSer.io_Command = CMD_READ;
-
- /* Give the start address of our data buffer: */
- ioreq->IOSer.io_Data = data;
-
- /* We want to read 400 bytes/characters: (The buffer must */
- /* then be at least 400 bytes.) */
- ioreq->IOSer.io_Length = 400;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* Everything OK? */
- if( error )
- printf( "Problems while reading!\n" );
-
-
- The program above will go to sleep while the data is collected
- from the serial port. However, sometimes you may want to do
- something while the data is fetched and not go to sleep.
- Instead of using the function DoIO() you should then use the
- asynchronous SendIO(). As explained in chapter 17 DEVICES, the
- SendIO() will not wait for the request to be completed.
-
- To check if the request have been completed or not you can
- either use the function CheckIO(), or wait for a message to
- arrive at the request block's reply port.
-
- Once the request have been completed you can look at the
- io_Error field of the request block to check if everything
- was OK. If the field is zero everything was executed without
- any problems, but if it is non zero the request failed.
-
- Here is an example:
-
- /* Declare a pointer and set it to NULL: */
- struct IOExtSer *ptr = NULL;
-
- ...
-
-
- /* We want to read some data: */
- ioreq->IOSer.io_Command = CMD_READ;
-
- /* Give the start address of our data buffer: */
- ioreq->IOSer.io_Data = data;
-
- /* We want to read 400 bytes/characters: (The buffer must */
- /* then be at least 400 bytes.) */
- ioreq->IOSer.io_Length = 400;
-
- /* Do our request and return immediately: */
- SendIO( ioreq );
-
-
- /* As long as the pointer is not pointing to */
- /* the request we should stay in the loop: */
- while( ptr == NULL )
- {
- ... do something ...
-
-
- /* Check if the request has been completed: (If the */
- /* request has been completed CheckIO() will return */
- /* a pointer to the request, else NULL is returned.) */
- ptr = CheckIO( ioreq );
- }
-
- /* Remove the request block's message. (The ptr and ioreq */
- /* are in this example identical, so it does not matter */
- /* whichever you will use. The parenthesis around the */
- /* expression is actually unnecessary, but this looks */
- /* better.) */
- Remove( &(ptr->IOSer.io_Message.mn_Node) );
-
- /* Everything OK? Check the io_Error filed: */
- if( ioreq->IOSer.io_Error )
- printf( "Problems while reading!\n" );
-
-
- Finally their exist a special "quick" mode. It can only
- sometimes be used and only for reading. This special mode
- can be used when a lot of data at a very (!) high speed
- should be collected. The "quick" mode is not the same as the
- "SERF_RAD_BOOGIE" mode explained above. The quick mode can
- only be used for reading, and there are some special
- restrictions, while the high speed rad boogie mode can be
- used both for reading and writing.
-
- To use the quick mode you set the IOF_QUICK flag, before
- you send the request. You should then not use the normal DoIO()
- or SendIO() functions, but instead the low level BeginIO()
- function. The BiginIO() is synchronous (like DoIO()) if we
- were allowed to use quick mode, else the request is
- asynchronous (like SendIO()).
-
- Although you want to use the quick mode, it is not sure you
- are allowed to do it. For some requests it is OK, others
- will automatically remove the IOF_QUICK flag. You must
- therefore check the request after you have posted it to
- see if the IOF_QUICK flag is still on or not. If the flag was
- removed, the quick mode was turned off and the request should
- now be treated as those started with a SendIO() call (remember
- to remove the message). However, it the flag is still there
- the quick mode was used and we do not need (nor should) remove
- any message at the reply port.
-
- /* Initialize the request block as normal. */
- /* ... */
-
- /* Try to use the "quick" mode: */
- ioreq->IOSer.io_Flags = IOF_QUICK;
-
- /* Do the request: */
- BeginIO( ioreq );
-
- if( (ioreq->IOSer.io_Flags & IOFQUICK) )
- {
- /* OK! The request was using quick mode, which means */
- /* that our task was put to sleep while the data was */
- /* fetched, and the request have now been completed. */
- /* Since we are using quick mode there are no message */
- /* that should be removed. */
- }
- else
- {
- /* Too bad, we were not allowed to use the quick mode. */
- /* The request should now be treated as if it was */
- /* started with a SendIO() function call. This request */
- /* is asynchronous - request returns immediately. */
-
- /* We can either use the routine above with CheckIO() */
- /* or put our task to sleep while we are waiting, by */
- /* calling the WaitIO() function. The WaitIO() */
- /* function will automatically remove the message, so */
- /* we do not need to do anything more. However, if we */
- /* used the function Wait(), we have to remove the */
- /* messages ourself. */
- WaitIO( ioreq );
- }
-
-
- The "quick" mode can only sometimes be used:
-
- 1. You may only read data. The "quick" mode is not allowed for
- writing.
-
- 2. There is enough data in the internal input buffer so the
- request will immediately be satisfied.
-
- 3. No other requests is using/waiting for the serial port.
-
-
-
- 7.3.5 WRITE DATA
-
- When you want to write data to the serial port it is almost the
- same procedure as when reading. The only difference is that you
- set the command flag "CMD_WRITE".
-
- Here is an example on how to write data to the serial port:
- (Your program will be put to sleep while the data is moved to
- the serial port.)
-
- error: (UBYTE) is a simple unsigned byte variable.
-
- ioreq: (struct IOExtSer *) is a pointer to an IOExtSer
- structure.
-
- data: (BYTE) is a pointer to a block of memory where all
- data you want to send is stored.
-
-
- /* We want to send (write) some data: */
- ioreq->IOSer.io_Command = CMD_WRITE;
-
- /* Give the start address of our data buffer: */
- ioreq->IOSer.io_Data = data;
-
- /* We want to send 150 bytes/characters: */
- ioreq->IOSer.io_Length = 150;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* Everything OK? */
- if( error )
- printf( "Problems while writing!\n" );
-
-
- The program above will go to sleep while the data is copied to
- the serial port. If you do not want the program to wait for the
- request to be completed you should use SendIO(). The procedure
- is very similar with reading.
-
- To check if the request have been completed or not you can
- either use the function CheckIO(), or wait for a message to
- arrive at the request block's reply port.
-
- Once the request have been completed you can look at the
- io_Error field of the request block to check if everything
- was OK. If the field is zero everything was executed without
- any problems, but if it is non zero the request failed.
-
- Here is an example:
-
- /* Declare a pointer and set it to NULL: */
- struct IOExtSer *ptr = NULL;
-
- ...
-
-
- /* We want to send (write) some data: */
- ioreq->IOSer.io_Command = CMD_WRITE;
-
- /* Give the start address of our data buffer: */
- ioreq->IOSer.io_Data = data;
-
- /* We want to send 280 bytes/characters: */
- ioreq->IOSer.io_Length = 280;
-
- /* Do our request and return immediately: */
- SendIO( ioreq );
-
-
- /* As long as the pointer is not pointing to */
- /* the request we should stay in the loop: */
- while( ptr == NULL )
- {
- ... do something ...
-
-
- /* Check if the request has been completed: (If the */
- /* request has been completed CheckIO() will return */
- /* a pointer to the request, else NULL is returned.) */
- ptr = CheckIO( ioreq );
- }
-
- /* Remove the requst block's message. (The ptr and ioreq */
- /* are in this example identical, so it does not matter */
- /* whichever you will use. The parenthesis around the */
- /* expression is actually unnecessary, but this looks */
- /* better.) */
- Remove( &(ptr->IOSer.io_Message.mn_Node) );
-
- /* Everything OK? Check the io_Error filed: */
- if( ioreq->IOSer.io_Error )
- printf( "Problems while writing!\n" );
-
-
- You can not use the quick mode while you are sending data. If
- you need fast communication you should set the serial flag
- "SERB_RAD_BOOGIE". Note the restrictions mentioned above. (Only
- eight-bit characters, and no parity checking etc...)
-
-
- Since you usually will want to read and write data at the same
- time, you have to use two separate request blocks. If you are
- using shared access mode you simply create two request blocks
- and open the serial device twice. (Do not forget to close both
- requests later on.) Here is an example:
-
- struct MsgPort *replymp;
- struct IOExtSer *serial_req_read;
- struct IOExtSer *serial_req_write;
- UBYTE error;
-
-
- /* We use only one reply message port: */
- replymp = (struct MsgPort *)
- CreatePort( NULL, 0 );
- if( !replymp )
- clean_up( "Could not create the reply port!" );
-
-
- /* Create the request block "read": */
- serial_req_read = (struct IOExtSer *)
- CreateExtIO( replymp, sizeof( struct IOExtSer ) );
- if( !serial_req_read )
- clean_up( "Not enough memory!" );
- serial_req_read->io_SerFlags = SERF_SHARED|SERF_7WIRE;
-
- /* Create the request block "write": */
- serial_req_write = (struct IOExtSer *)
- CreateExtIO( replymp, sizeof( struct IOExtSer ) );
- if( !serial_req_write )
- clean_up( "Not enough memory!" );
- serial_req_write->io_SerFlags = SERF_SHARED|SERF_7WIRE;
-
-
- /* Open the serial device for the read request: */
- error = OpenDevice( SERIALNAME, 0, serial_req_read, 0 );
- if( error )
- clean_up( "Could not open the serial device (Read)!" );
-
- /* Open the serial device for the write request: */
- error = OpenDevice( SERIALNAME, 0, serial_req_write, 0 );
- if( error )
- clean_up( "Could not open the serial device (Write)!" );
-
-
- If you are using exclusive access mode you can of course not
- open the serial device twice. Instead we have to copy the
- first request block to the other request block, byte for byte.
- Here is an example:
-
- struct MsgPort *replymp;
- struct IOExtSer *serial_req_read;
- struct IOExtSer *serial_req_write;
- BYTE *r_ptr;
- BYTE *w_ptr;
- UBYTE error;
- int loop;
-
-
- /* We use only one reply message port: */
- replymp = (struct MsgPort *)
- CreatePort( NULL, 0 );
- if( !replymp )
- clean_up( "Could not create the reply port!" );
-
-
- /* Create the request block "read": */
- serial_req_read = (struct IOExtSer *)
- CreateExtIO( replymp, sizeof( struct IOExtSer ) );
- if( !serial_req_read )
- clean_up( "Not enough memory!" );
- serial_req_read->io_SerFlags = SERF_SHARED|SERF_7WIRE;
-
- /* Create the requestblock "write": */
- serial_req_write = (struct IOExtSer *)
- CreateExtIO( replymp, sizeof( struct IOExtSer ) );
- if( !serial_req_write )
- clean_up( "Not enough memory!" );
- serial_req_write->io_SerFlags = SERF_SHARED|SERF_7WIRE;
-
-
- /* Open the serial device for the read request: */
- error = OpenDevice( SERIALNAME, 0, serial_req_read, 0 );
- if( error )
- clean_up( "Could not open the Serial Device (Read)!" );
-
-
- /* Since we can not open the serial device once again */
- /* for the write request, we have to copy the whole */
- /* read request block into the write request block. */
-
- /* Get the start address of both request blocks: */
- r_ptr = (BYTE *) serial_req_read;
- w_ptr = (BYTE *) serial_req_write;
-
- /* Copy the request block, byte by byte: */
- for( loop=0; loop < sizeof( struct IOExtSer ); loop++ )
- {
- /* Copy one byte: */
- *w_ptr = *r_ptr;
-
- /* Step one byte forward: */
- w_ptr++;
- r_ptr++;
- }
-
-
- Now we have two request blocks, and can therefore use both
- read and write requests at the same time. If you also want to
- use the special extra functions described further down, you
- may want to create even one more request block (or maybe
- even more...). The procedure is the same as described above.
-
-
-
- 7.3.6 ERRORS
-
- While you are using the serial device several errors may
- occur. The most common problem is that some other program is
- already using the serial port, but it can happen that data has
- been corrupted while reading/writing (the parity checking is
- a simple way to find these errors).
-
- There exit for the moment nine different types of serial port
- errors, all defined in the header file "devices/serial.h".
- You will receive the error message from the function you
- just called, or you can check a request block to see if there
- were any problems. (The io_Error filed of the request block
- either contains 0, which means everything is OK, or an error
- number.)
-
- Here is a complete list of the serial error messages:
-
- SerErr_DevBusy Some other task/request is already
- using the serial device.
-
- SerErr_BufErr: The serial device could not allocate
- enough memory for the internal input
- buffer.
-
- SerErr_InvParam: The request block's parameters were not
- properly initialized.
-
- SerErr_LineErr: The serial cable is faulty or the other
- device is not properly initialized or
- not connected. Tell the user to check the
- cables!
-
- SerErr_ParityErr: The data you just sent/received contained
- at least one byte which was corrupted.
- Note that the serial flag "SERF_PARITY_ON"
- must be set, else the device will not
- check for errors.
-
- SerErr_TimerErr: There was some problem with the timer.
-
- SerErr_BufOverflow: The serial input buffer has been filled.
- You should empty it as fast as possible
- so you do not lose valuable information.
-
- SerErr_NoDSR: No DSR.
-
- SerErr_DetectedBreak: A break was detected.
-
-
- While you are using the serial device it may happen that you
- receive other error messages than described above. It is
- then usually the Exec which sent them: (defined in the header
- file "exec/errors.h")
-
- IOERR_OPENFAIL The device (unit) could not be opened. (If you
- are denied access to the serial device you
- should receive the SerErr_DevBusy flag instead
- of this exec message, but internally this flag
- is used.)
-
- IOERR_ABORTED When you abort a previously started request by
- calling the AbortIO() function, the io_Error
- filed of that request is set to IOERR_ABORTED.
- If you find a request block with this flag set,
- you know that it has been aborted.
-
- IOERR_NOCMD You tried to use a command that is not
- supported by the serial device.
-
- IOERR_BADLENGTH The length of the request was not valid.
-
-
-
- 7.3.7 CLEAN UP
-
- As usual on the Amiga you must remember to close and return
- everything you have opened or allocated. If you do not close
- the serial device after you, other programs will then not
- be able to use the serial port. PLEASE be very careful about
- this!
-
- Here is a list of what you have to do:
-
- 1. All requests you have started with SendIO() or BeginIO()
- (asynchronous commands) must either have been completed
- or aborted before you may close the device. It is a very
- common error to forget this, and it can be hard to find
- this bug. Usually the program will work fine (the command
- was completed in time), but now and then your program will
- crash (the command was completed after the device have
- been closed).
-
- A simple way is to abort all commands that have not
- reported that they have been completed, but this is not
- always good way to do it. (The last commands may be
- important and should therefore not be aborted.)
-
- If you do not want to abort the command, you should
- instead wait for it to be completed. The WaitIO()
- function is simple to use, and will put your program
- to sleep while waiting, so no computer time is wasted.
- If the request has already been completed, the function
- will return immediately. WaitIO() will also remove the
- message from the reply port. It is a very useful and
- simple function to use, but do NOT try to wait for
- a request that has not been started! (It will then be
- a very long wait, probably some million years before
- the user realizes that he/she has to hit the reset keys.)
-
- Here is an example on how to wait for a request to be
- completed: (If the request already has been completed
- it does not matter, WaitIO() will then simply return
- immediately. Note that we do not have to remove any
- messages from the reply port if we use WaitIO().)
-
- /* Store possible error numbers here: */
- UBYTE error;
-
- /* ... */
-
- /* Wait for the request to be completed: */
- error = WaitIO( ioreq );
-
- /* Everything OK? */
- if( error )
- printf( "Something went wrong!" );
-
- /* Well, successful or not, we may now */
- /* close the device! */
-
-
- To abort a request, simply use the AbortIO() function:
-
- /* Try to abort a previously started request: */
- /* (Do not try to abort a request that has not */
- /* been started.) */
- AbortIO( ioreq );
-
-
- 2. When all requests have been completed or aborted you may
- close the serial device. (Requests that have been executed
- by calling the DoIO() function have already been completed
- before your program wakes up, and thus you do not need to
- wait for these.)
-
- The serial device is closed as all other devices, by
- calling the CloseDevice() function. Here is an example:
-
- /* Close the Serial Device: */
- if( !serial_dever )
- CloseDevice( ioreq );
-
-
- 3. You should now return all request blocks you have
- allocated. If you allocated a standard sized request block
- by calling the CreateStdIO() function, you should free
- it by calling the DeleteStdIO() function. However, if
- you have allocated an extended request block (like the
- serial device's request blocks) by calling the
- CreateExtIO() function, you MUST call the DeleteExtIO(),
- and of course remove the same amount of data as you
- allocated.
-
- How to delete a standard request block: (Since it is of
- the standard size, you do not need to specify any size.)
-
- /* Deallocate a standard sized request block: */
- DeleteStdIO( ioreq );
-
- With extended request block you have to specify the size
- as you did when you allocated it:
-
- /* Deallocate an extended request block: */
- /* (The size may vary depending on what */
- /* device it was used for.) */
- DeleteExtIO( ioreq, sizeof( struct IOExtSer ) );
-
- Note that ALL request blocks that have been allocated,
- must be removed!
-
-
- 4. Finally you should close all message ports you have
- previously opened. Simply use the DeletePort() function
- as this example demonstrates:
-
- /* Remove the replyport: */
- DeletePort( replymp);
-
-
- It can not be said to often. Please be careful with how your
- program terminates! Your program should not only run fine,
- but it should also allow other programs to run after and
- simultaneously. Remember that your program must also be able
- to quit nice and neatly even if it had to terminate too
- early because of some fatale error. The cleaning up should
- only be done where it is needed, and if you have not allocated
- the memory or opened the device before your program quits, you
- should of course NOT try to free these resources! If you do the
- Amiga will most certainly crash! Too many programs contain this
- very annoying error.
-
- The best way to manage this cleaning up routine is to write a
- separate function which checks each thing before it frees it.
- The idea is that you may call this routine at any time, and it
- will still manage to clear everything properly. Here is an
- example: (Note how we check each thing to see if it should be
- removed!)
-
- /* Close and return everything that has been */
- /* opened and allocated before we quit: */
- void clean_up()
- {
- /* 1. Close the Serial Device: */
- if( !serial_dever )
- CloseDevice( serial_req );
-
- /* 2. Deallocate the serial request block: */
- if( serial_req )
- DeleteExtIO( serial_req, sizeof( struct IOExtSer ) );
-
- /* 3. Remove the replyport: */
- if( replymp )
- DeletePort( replymp);
-
- /* 4. Quit: */
- exit( 0 );
- }
-
- Comments: 1. The serial_dever is a variable that we have
- declared ourself, and is used only to determine
- if the device has been opened or not. (The
- variable is set to TRUE before the program
- starts, and is only changed to FALSE after
- a successful opening of the device. See the
- included examples for more information.) We
- should of course only close the device if
- the serial_dever is FALSE. ("serial_dever"
- stands for "serial device error".)
-
- 2. The serial_req is a pointer which is either
- pointing to a request block, or NULL if no
- request block has been allocated. We should
- of course only free the request block if there
- exist one.
-
- 3. The replymp is a pointer which is either
- pointing to a message port, or NULL if no message
- port has been opened. And of course, we should
- only close the message port if it has been
- opened.
-
- 4. Finally our program may terminate. The exit()
- function is placed here so we are sure the
- program will quit. (If we did not have this
- exit(), our function would then return the
- control to our program again, and then we would
- have serial (sorry, serious) problems.
-
-
-
- 7.4 A COMPLETE EXAMPLE
-
- Here is a complete example that opens the serial device, sets
- all necessary parameters, sends some data, collects some data
- and finally cleans up and quits. Since we send the read and
- write requests after each other (the first is completed before
- the other is started) we only need to use one request block.
-
-
- #include <exec/types.h>
- #include <devices/serial.h>
-
-
- /* Declare a pointer to our reply port: */
- struct MsgPort *replymp = NULL;
-
- /* Declare a pointer to our serial request block: */
- struct IOExtSer *serial_req = NULL;
-
- /* Store the serial device error here: */
- UWORD serial_dever = TRUE;
-
- /* Declare our own data buffer: (Big enough to hold 300 bytes.) */
- BYTE buffer[ 300 ];
-
-
- /* Declare our functions: */
- void main();
- void clean_up( STRPTR text );
-
- void main()
- {
- int loop;
- UBYTE *ptr;
- UBYTE error;
-
- /* The eight end-of-file characters: */
- UBYTE eof_char[8]={ 0x06, 0x05, 0x04, 0x03,
- 0x02, 0x01, 0x00, 0x00 };
-
-
-
- /* OPEN THE SERIAL DEVICE: */
-
- /* Get a reply port: (No name, priority 0) */
- replymp = (struct MsgPort *)
- CreatePort( NULL, 0 );
- if( !replymp )
- clean_up( "Could not create the reply port!" );
-
- /* Create a serial request block: */
- serial_req = (struct IOExtSer *)
- CreateExtIO( replymp, sizeof( struct IOExtSer ) );
- if( !serial_req )
- clean_up( "Not enough memory for the serial request block!" );
-
- /* Open the Serial Device: */
- serial_dever = OpenDevice( SERIALNAME, 0, serial_req, 0 );
- if( serial_dever )
- clean_up( "Could not open the Serial Device!" );
-
-
-
-
- /* SET THE SERIAL PARAMETERS: */
-
- /* Set the Serial Device's own input buffer to 512 bytes: */
- serial_req->io_RBufLen = 512;
-
- /* Set baud rate to 9600 baud: */
- serial_req->io_Baud = 9600;
-
- /* Set break time to half a second: */
- serial_req->io_BrkTime = 500000;
-
- /* Read 8 bits per character: */
- serial_req->io_ReadLen = 8;
-
- /* Write 8 bits per character: */
- serial_req->io_WriteLen = 8;
-
- /* Use 1 stop bit: */
- serial_req->io_StopBits = 1;
-
- /* Use parity and end-of-file characters: */
- serial_req->io_SerFlags = SERF_PARTY_ON | SERF_EOFMODE;
-
- /* No additional flags: */
- serial_req->io_ExtFlags = NULL;
-
- /* Set all eight end of file characters: */
- ptr = (UBYTE *) &(serial_req->io_TermArray);
- for( loop=0; loop < 8; loop++ )
- {
- /* Copy character after character: */
- *ptr = eof_char[ loop ];
- /* Step one byte forward: */
- ptr++;
- }
-
- /* All values have now been set, lets do a SDCMD_SETPARAMS request: */
- serial_req->IOSer.io_Command = SDCMD_SETPARAMS;
-
- /* Do our request: */
- error = DoIO( serial_req );
- if( error )
- clean_up( "Could not set the serial parameters!" );
-
-
-
- /* SEND DATA TO THE SERIAL PORT: */
-
- /* Put the data we want to send to the serial port into */
- /* our own data buffer: (Well in this example we only */
- /* send two bytes.) */
- buffer[ 0 ] = 0x4C;
- buffer[ 1 ] = 0x31;
-
- /* We want to send (write) some data: */
- serial_req->IOSer.io_Command = CMD_WRITE;
-
- /* Give the start address of our data: */
- serial_req->IOSer.io_Data = (APTR) buffer;
-
- /* We want to send two bytes: */
- serial_req->IOSer.io_Length = 2;
-
- /* Do our request: */
- error = DoIO( serial_req );
- if( error )
- clean_up( "Could not send data to the serial port!" );
-
-
-
- /* READ DATA FROM THE SERIAL DEVICE: */
-
- /* We want to read some data: */
- serial_req->IOSer.io_Command = CMD_READ;
-
- /* Give the start address of our buffer: */
- serial_req->IOSer.io_Data = (APTR) buffer;
-
- /* We want to read 0 bytes: */
- /* (If you do not have anything connected to your serial */
- /* port, we better not wait for any signals, thus read */
- /* only 0 bytes.) */
- serial_req->IOSer.io_Length = 0;
-
- /* Do our request: */
- error = DoIO( serial_req );
- if( error )
- clean_up( "Could not read data from the serial port!" );
-
-
-
- /* THE END: */
- clean_up( "The End" );
- }
-
-
- /* Close and return everything that has been */
- /* opened and allocated before we quit: */
- void clean_up( STRPTR text )
- {
- /* Close the Parallel Device: */
- if( !serial_dever )
- CloseDevice( serial_req );
-
- /* Deallocate the serial request block: */
- if( serial_req )
- DeleteExtIO( serial_req, sizeof( struct IOExtSer ) );
-
- /* Remove the replyport: */
- if( replymp )
- DeletePort( replymp);
-
- /* Print the message: */
- printf( "\n%s\n", text );
-
- /* Quit: */
- exit( 0 );
- }
-
-
-
- 7.5 OTHER USEFUL COMMANDS
-
- You can not only read and write from/to the serial port. There
- exist several other functions that can sometimes be needed.
- Here is a complete list:
-
- 1. Break, stop the serial device for a short time.
- 2. Clear, clear the input buffer.
- 3. Flush, removes all queued requests.
- 4. Query, get some information from the serial device.
- 5. Reset, reinitializes the serial device.
- 6. Start, restarts the serial communication.
- 7. Stop, temporary stops the serial communication.
-
-
-
- 7.5.1 BREAK
-
- While you are sending or reading data you sometimes have to
- take a small pause. Your program may for example need to empty
- the data buffer, or coordinate its action with some other task.
- To pause the serial device you simply send a break request,
- and all communications is halted for a specified time.
-
- You send a break signal by setting the io_Command field to
- "SDCMD_BREAK". The default is that all serial requests are
- immediately halted, but if the serial flag "SERF_QUEUEDBRK"
- is set, the break command will be queued as all other requests
- and the device will first take a break when all previous
- requests have been completed.
-
- The serial device will normally take a 250000 microseconds
- (1/4 seconds) long break, but you may change this break time
- by altering the serial device's "io_BrkTime" parameter.
-
- Here is an example on how you can send a break command:
-
- /* We want to take a pause: */
- ioreq->IOSer.io_Command = SDCMD_BREAK;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* OK? */
- if( error )
- printf( "Problems with the break!\n" );
-
-
-
- 7.5.2 CLEAR
-
- While you are reading data from the serial device, it is
- actually first stored in the internal input buffer, and then
- moved to your own buffer when requested. If you want to clear
- the buffer before you start to read you should set the
- io_Command field to "CMD_CLEAR". Here is an example:
-
- /* We want to clear the input buffer: */
- ioreq->IOSer.io_Command = CMD_CLEAR;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* OK? */
- if( error )
- printf( "Could not clear the input buffer!\n" );
-
-
-
- 7.5.3 FLUSH
-
- If several requests are sent to the device they are all queued
- on a FIFO (First In First Out) basis. The command "CMD_FLUSH"
- can then be used to remove all these queued commands. Here
- is an example:
-
- /* We want to remove all queued requests: */
- ioreq->IOSer.io_Command = CMD_FLUSH;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* OK? */
- if( error )
- printf( "Could not remove the queued requests!\n" );
-
-
-
- 7.5.4 QUERY
-
- The command "SDCMD_QUERY" can be used to get some information
- from the serial device. It is useful if you want to see the
- serial status and/or how many bytes there are already in the
- internal input buffer. The "io_Status" field of the request
- structure will be set as following table shows:
-
- Bit Hex Active Description
- ---------------------------------------------------------------
- 0 0x0001 - Reserved
- 1 0x0002 - Reserved
- 2 0x0004 High Connected to par. "select" and ser. "ring"
- 3 0x0008 Low DSR - Data Set Ready
- 4 0x0010 Low CTS - Clear To Send
- 5 0x0020 Low DCD - Carrier Detect
- 6 0x0040 Low RTS - Ready To Send
- 7 0x0080 Low DTR - Data Terminal Ready
- 8 0x0100 High Read overrun
- 9 0x0200 High Break sent
- 10 0x0400 High Break received
- 11 0x0800 High Transmit X-OFF
- 12 0x1000 High Receive X-OFF
- 13 0x2000 - Reserved
- 14 0x4000 - Reserved
- 15 0x8000 - Reserved
- ---------------------------------------------------------------
-
- The field "io_Actual" of the request structure contains the
- number of bytes still left in the internal input buffer. Here
- is an example:
-
- /* Check the serial device: */
- ioreq->IOSer.io_Command = SDCMD_QUERY;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* OK? */
- if( error )
- printf( "Could not get any information from the device!\n" );
- else
- {
- /* Check the "io_Status" field: */
- if( ioreq->io_Status & 0x0200 )
- printf( "A break request have just been sent!\n" );
-
- /* Check number of characters left in the input buffer: */
- printf( "Characters left: %ld\n", ioreq->IOSer.io_Actual );
- }
-
-
-
- 7.5.5 RESET
-
- Send the command "CMD_RESET" to reset the serial device. All
- commands that are queued to the device will be removed, commands
- that are currently executed will be aborted, the internal input
- buffer will be cleared and reallocated to the default size and
- finally all serial flags are resetted. Here is an example:
-
- /* We want to reset the serial device: */
- ioreq->IOSer.io_Command = CMD_RESET;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* OK? */
- if( error )
- printf( "Could not reset the serial device!\n" );
-
-
-
- 7.5.6 START
-
- After you have stopped the serial communication by sending an
- X-OFF message to the other device, you may want to start the
- communication again. It is done by sending an X-ON message,
- and the external device will then know that it may start to
- send/receive data. X-ON messages are sent to the other device
- (as well to our self) by issuing a "CMD_START" command. Here
- is an example:
-
- /* We want to start serial communication again: */
- ioreq->IOSer.io_Command = CMD_START;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* OK? */
- if( error )
- printf( "Could not start the serial communication!\n" );
-
-
-
- 7.5.7 STOP
-
- To temporary stop all serial communication you send a
- "CMD_STOP" command. If you try to stop the communication an
- X-OFF message will be sent to the external device (as well as
- to all other programs currently using the serial device). When
- a X-OFF message has been received, communication will first
- start again when an X-ON message is sent. (See CMD_START.) Here
- is an example:
-
- /* We want to temporary stop all serial communication: */
- ioreq->IOSer.io_Command = CMD_STOP;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* OK? */
- if( error )
- printf( "Could not stop the serial communication!\n" );
-
-
-
- 7.6 FUNCTIONS
-
- DoIO()
-
- DoIO() is used to send requests to a device, and waits for it
- to be completed. While the program is waiting it is put to
- sleep so it will not waste any computer time. DoIO() will
- return first when the request have been completed or failed,
- and no message is therefore sent to the reply port.
-
- Synopsis: error = DoIO( req );
-
- error: (long) DoIO() will return first when the request has
- been completed or something has failed. If the
- request was successfully completed zero is returned,
- else an error number is returned. What error number
- depends on which device was used.
-
- req: (struct IORequest *) Pointer to the request you
- want to have executed.
-
-
- SendIO()
-
- SendIO() is used to send requests to a device, but will
- return immediately without any delay. To check if the request
- have been completed use the CheckIO() function, or look
- at the request's reply port for any messages. Once the
- request has been completed you must remove the message at
- the reply port. (CheckIO() will not do it.) To remove a
- message use the function Remove(). Note that you may NOT
- close the serial device before all requests have been
- completed or aborted!
-
- Synopsis: SendIO( req )
-
- req: (struct IORequest *) Pointer to the request you
- want to have executed.
-
-
- CheckIO()
-
- CheckIO() is used to check if a previously started request
- has been completed. Note that this function will not remove
- the message at the reply port. This must be done with the
- Remove() function.
-
- Synopsis: ptr = CheckIO( req );
-
- ptr: (long) CheckIO() will either return NULL if the
- request have not been completed or it will return a
- pointer to the request block.
-
- req: (struct IORequest *) Pointer to the request you
- want to check.
-
-
- WaitIO()
-
- WaitIO() will wait for the request to be completed, and while
- the program is waiting it is put to sleep so no computer time
- is wasted.
-
- Synopsis: error = WaitIO( req );
-
- error: (long) WaitIO() will return first when the request,
- that has previously been sent, has been completed or
- something has failed. If the request was successfully
- completed zero is returned, else an error number is
- returned. What error number depends on which device
- was used.
-
- req: (struct IORequest *) Pointer to the request you
- want to wait for to be completed. Note that the
- request must have already been sent to the device
- by either a SendIO() or BeginIO() function call.
-
-
- BeginIO()
-
- BeginIO() is a low level form of the SendIO() function. The
- advantage with BeginIO() is that no fields of the request
- block will be altered as which is the case with SendIO(). If
- you are for example using the "quick mode" you should not
- use SendIO() since it will alter some of the data blocks.
-
- BeginIO() is synchronous command if you use the quick mode,
- but if you are not, the command will be asynchronous. Note
- that you may NOT close the serial device before all requests
- have been completed or aborted, so be careful with
- asynchronous commands.
-
- Synopsis: BeginIO( req )
-
- req: (struct IORequest *) Pointer to the request you
- want to have executed. BeginIO() will not alter any
- values in this request structure as which is the case
- with SendIO() and DoIO(). Normally this is not any
- problem, and thus the SendIO() and DoIO() functions
- should be used. However, with the Audio Device for
- example some of these fields which are altered should
- not be changed, and you should therefore use this
- low level function BeginIO().
-
-
- AbortIO()
-
- AbortIO() will try to abort a previously started request. This
- function should be used sparsely since it does not look so
- good if you start a request and the try to stop it. (Better
- not start it at all.) However, it is easy, and can sometimes
- be very useful.
-
- A request that is aborted will have its io_Error field set
- to IOERR_ABORTED (defined in header file "exec/errors.h").
-
- Synopsis: AbortIO( req )
-
- req: (struct IORequest *) Pointer to the request you
- want to abort.
-
-
- CloseDevice()
-
- CloseDevice() will (surprise!) close a device. If you close
- the serial device the internal input buffer will
- automatically be deallocated. Note that you should NOT close
- the device before all started asynchronous requests have been
- either completed or aborted.
-
- Synopsis: CloseDevice( ioreq );
-
- ioreg: (struct IORequest *) Pointer to the device's
- request block.
-
-
- OpenDevice()
-
- OpenDevice() will try to open the specified device.
-
- Synopsis: error = OpenDevice( name, unit, req, flags );
-
- error: (long) If OpenDevice() managed to open the device
- it returns 0, else an error number is returned.
- If you try to open the serial device, and there is
- already a program that is using it, the error
- message "SerErr_DevBusy" is returned.
-
- name: (char *) Name of the device you want to open.
- The name of the serial device is defined as
- SERIALNAME in header file "devices/serial.h".
-
- unit: (long) Which unit you want to open. Since there
- exist only one serial port, this field is ignored.
-
- req: (struct IORequest *) Pointer to a request block.
- For the serial device it must be a pointer to an
- extender serial request block (struct IOExtSer).
-
- flags: (long) Any special mode is set here. Ignored by
- the serial device.
-
-
-
- 7.7 COMMANDS
-
- Here is a complete list of commands you may send to the serial
- device. For full documentation se examples above.
-
- The special serial device commands: (Defined in header file
- "devices/serial.h")
-
- SDCMD_BREAK Sends a break signal.
- SDCMD_QUERY Check the status of the serial device.
- SDCMD_SETPARAMS Set the parameters of the serial device.
-
-
- The rest of the commands you may use are normal exec commands,
- and are defined in header file "exec/io.h".
-
- CMD_RESET Resets all parameters of the serial device.
- CMD_READ Read data from the serial port.
- CMD_WRITE Write data to the serial port.
- CMD_CLEAR Clears the internal input buffer.
- CMD_STOP Temporary stops all serial communication. (X-OFF)
- CMD_START Restarts serial communication. (X-ON)
- CMD_FLUSH Removes all queued requests.
-
-
-
- 7.8 EXAMPLES
-
- The included examples demonstrates how you can use the Serial
- Device. It demonstrates most of the features described in this
- chapter. Since I do not know what you have connected to your
- serial port the examples will not do very much. However, the
- examples are easy modify, so it should not be hard for you to
- change them as desired.
-
- Example 1
- If you have a Sharp JX-100 scanner you can run this program
- since it will try to turn the lamp on and then off again.
- Very useful! (hmmm...) The program does not check if there
- is any contact with the scanner, nor if the lamp really was
- turned on or not. It simply demonstrates how to send data.
-
- Example 2
- This example is rather similar to Example 1, but this time
- we do not wait for the serial port to complete our request.
- Instead we do somethings (well not very much) and now and
- then checks if the request has been completed. Using a busy
- wait.
-
- Example 3
- This example is also rather similar to Example 1, but this
- time we try to read and write at the same time. To be able
- to do several requests simultaneously we need one request
- block for each command. In this example we use three
- separate request blocks. Using asynchronous commands but
- puts the task to sleep just before we clear and return
- everything.
-
- Example 4
- This example does not do anything, but it consists of
- several useful functions that you can use yourself after
- small modifications. The functions demonstrates all
- commands there exist for the serial device, so if you
- had problems in understanding how a command was used you
- can look here.
-